#ifndef _IO_DGRAM_H_
#define _IO_DGRAM_H_

#include <ioudp.hpp>

#define	DGRAM_READ_ERROR			0x01
#define	DGRAM_READ_TIMEOUT			0x02
#define	DGRAM_WRITE_ERROR			0x04
#define	DGRAM_WRITE_TIMEOUT			0x08


class IoDgramBase : public IoUdpBase
{
public:
	IoDgramBase() {

	}
	virtual ~IoDgramBase() {

	}

public:
	int	async_read(NET_ADDR addr, NET_PORT port,
		BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		rc_assert(this->safe, S_ERROR)

		boost::asio::ip::udp::endpoint point(boost::asio::ip::address::from_string(addr), port);

		//no need try catch
		this->ptr->async_receive_from(boost::asio::buffer(this->ctx.rptr, this->ctx.rlen), point,
			safe->wrap(boost::bind(&IoDgramBase::dgram_handle_read,
				this,
				boost::asio::placeholders::error,
				boost::asio::placeholders::bytes_transferred)));

		return S_SUCCESS;
	}
	int	async_write(NET_ADDR addr, NET_PORT port,
		BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		rc_assert(this->safe, S_ERROR)

		boost::asio::ip::udp::endpoint point(boost::asio::ip::address::from_string(addr), port);

		//no need try catch
		this->ptr->async_send_to(boost::asio::buffer(this->ctx.wptr, this->ctx.wlen), point,
			safe->wrap(boost::bind(&IoDgramBase::dgram_handle_write,
				this,
				boost::asio::placeholders::error,
				boost::asio::placeholders::bytes_transferred)));

		return S_SUCCESS;
	}
	BUFFER_SIZE sync_read(NET_ADDR addr, NET_PORT port,
		BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		BUFFER_SIZE rc = S_IOERROR;

		try {
			boost::asio::ip::udp::endpoint point(boost::asio::ip::address::from_string(addr), port);
			rc = this->ptr->receive_from(boost::asio::buffer(buf, size), point);
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_IOERROR;
		}

		return rc;
	}
	BUFFER_SIZE sync_write(NET_ADDR addr, NET_PORT port,
		BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		BUFFER_SIZE rc = S_IOERROR;

		try {
			boost::asio::ip::udp::endpoint point(boost::asio::ip::address::from_string(addr), port);
			rc = this->ptr->send_to(boost::asio::buffer(buf, size), point);
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_IOERROR;
		}
		return rc;
	}


private:
	int dgram_handle_read(io_c_error_code ec,size_t rbytes) {

		if (ec) {
			this->DgramEventcb(this->ctx.data, DGRAM_READ_ERROR);
			return S_ERROR;
		}
		else {
			this->DgramReadcb(this->ctx.data, rbytes);
		}
		return S_SUCCESS;
	}

	int dgram_handle_write(io_c_error_code ec, size_t wbytes) {

		if (ec) {
			this->DgramEventcb(this->ctx.data, DGRAM_WRITE_ERROR);
			return S_ERROR;
		} else {

			this->DgramWritecb(this->ctx.data, wbytes);
		}
		return S_SUCCESS;
	}
	virtual void DgramWritecb(void *data, BUFFER_SIZE ulen)	= 0;
	virtual void DgramReadcb(void *data, BUFFER_SIZE ulen)	= 0;
	virtual void DgramEventcb(void *data, event_id what)	= 0;

};

#endif

